/*
 * @Author: jiu yin
 * @Date: 2024-12-30 14:55:54
 * @LastEditTime: 2025-02-20 17:20:13
 * @LastEditors: jiu yin zhen jing
 * @FilePath: \studio-web-admin\electron\node-socket-service\index.js
 */

const {rootPath}= require("./utils.js");

require("./envConfig/index.js");
const { device_online, web_ws } = require("./src/webSocket/store.js");
const logger = require("./src/service.js");
const message_fn = require("./src/webSocket/message.js");
const path = require("path");
const dgram = require("dgram");
const express = require("express");
const axios = require("axios");
const WebSocket = require("ws");
const http = require("http");
const router = require("./src/router");
let config = require("./config.js");
const wrapConfig = require(path.join(rootPath, "./wrapConfig.js"));
const app = express();
const server = dgram.createSocket("udp4");

require("./src/service.js");

// 创建 HTTP 服务器
const httpServer = http.createServer(app);

// 创建 WebSocket 服务器并指定端口
const wss = new WebSocket.Server({
	server: httpServer,
	perMessageDeflate: false, // 禁用消息压缩以提高性能
});

// 使用配置文件中的常量
const PORT = config.PORT;
const BROADCAST_ADDR = config.BROADCAST_ADDR;
const BROADCAST_PORT = config.BROADCAST_PORT;

//
const HEARTBEAT_TIMEOUT = 1000 * 30; // 心跳超时时间，30秒

// WebSocket 连接处理
wss.on("connection", (ws, req) => {
	const clientIP = req.socket.remoteAddress;
	logger.info("新的WebSocket连接已建立, 客户端IP:", clientIP);

	// 检查并清理同一 IP 的旧连接
	wss.clients.forEach(client => {
		if (client !== ws && client.clientIP === clientIP) {
			clearInterval(client.heartbeatCheck);
			client.terminate();
			logger.info(`清理同一IP(${clientIP})的旧连接`);
		}
	});

	// 标记当前连接的 IP
	ws.clientIP = clientIP;
	// lastHeartbeat 时间戳
	ws.lastHeartbeat = Date.now();
	const resetHeartbeat = () => {
		ws.heartbeatCheck = setInterval(() => {
			const timeElapsed = Date.now() - ws.lastHeartbeat;
			logger.info(`心跳检测相差时间${timeElapsed},clientIP:${clientIP} ${new Date().toLocaleString()}`);
			if (timeElapsed > HEARTBEAT_TIMEOUT) {
				clearInterval(ws.heartbeatCheck);
				ws.terminate();
				logger.info(`客户端 ${clientIP} 心跳超时，关闭连接`);
			}
		}, HEARTBEAT_TIMEOUT);
	};
	// 初始化当前连接的心跳检测
	resetHeartbeat();

	// 处理接收到的消息
	ws.on("message", message => {
		try {
			let JSON_message = JSON.parse(message);
			if (JSON_message.action == "/heartbeat") {
				ws.lastHeartbeat = Date.now();
				logger.info(`最后心跳时间 ${ws.clientIP} ${new Date(ws.lastHeartbeat).toLocaleString()}`);
				ws.send(JSON.stringify({ action: JSON_message?.action, payload: {}, code: 200, type: JSON_message?.type }));
			}
			message_fn.message(ws, clientIP, JSON_message);
		} catch (error) {
			logger.error("JSON解析错误:", error);
			logger.error("错误信息:", message.toString());
			ws.send(JSON.stringify({ error: "Invalid JSON format" }));
		}
	});

	// 处理连接关闭
	ws.on("close", (code, reason) => {
		logger.info(`客户端断开连接, IP: ${clientIP}, 代码: ${code}, 原因: ${reason}`);
		clearOnline(clientIP);
		clearInterval(ws.heartbeatCheck);
	});

	// 发送欢迎消息
	ws.send(JSON.stringify({ open: "WebSocket连接已建立" }));
});

// 监听 WebSocket 服务器错误
wss.on("error", error => {
	console.error("WebSocket 服务器错误:", error);
});

// 创建Express路由
app.get("/", (req, res) => {
	res.send("UDP 广播服务器和WebSocket服务器正在运行");
});

// 广播函数
function startBroadcast() {
	setInterval(() => {
		const message = JSON.stringify({
			serverAddress: config.SERVER_IP,
			serverPort: PORT,
			message: "",
		});

		server.send(message, BROADCAST_PORT, BROADCAST_ADDR, err => {
			if (err) {
				console.error("发送广播失败:", err);
			} else {
				// logger.info("广播已发送");
			}
		});
	}, 5000);
}

// UDP服务器错误处理
server.on("error", err => {
	console.error("UDP服务器错误:", err);
	server.close();
});

//清理在线状态
function clearOnline(clientIP) {
	let index = device_online.findIndex(item => item.clientIP == clientIP);
	if (index > -1) {
		web_ws.forEach(item => {
			message_fn.successSend({
				ws: item,
				action: "/api/device/offline",
				type: "web",
				payload: { sn: device_online[index].sn },
			});
		});
		device_online.splice(index, 1);
	}
	if (web_ws.has(clientIP)) web_ws.delete(clientIP);
	logger.info(
		"存储在线设备",
		device_online.length,
		device_online.map(item => ({ clientIP: item.clientIP, sn: item.sn }))
	);
	logger.info(
		"存储web端",
		[...web_ws.keys()].length,
		[...web_ws.keys()].map(item => ({ clientIP: item }))
	);
}

// 优雅退出
process.on("SIGINT", () => {
	logger.info("正在关闭服务器...");
	wss.close(() => {
		logger.info("WebSocket 服务器已关闭");
		httpServer.close(() => {
			logger.info("HTTP 服务器已关闭");
			server.close(() => {
				logger.info("UDP 服务器已关闭");
				process.exit(0);
			});
		});
	});
});

// CORS 中间件
app.use((req, res, next) => {
	res.header("Access-Control-Allow-Origin", "*");
	res.header("Access-Control-Allow-Methods", "GET, POST, OPTIONS");
	res.header("Access-Control-Allow-Headers", "Content-Type");
	next();
});

// 错误处理中间件
app.use((err, req, res, next) => {
	console.error("服务器错误:", err);
	res.status(500).send("服务器错误");
});

async function updatePlaceWebSocketAddress() {
	if (!wrapConfig.PLACE_ID) return logger.error("config文件下没有配置place_id不能远程存储当前ws地址");
	console.log("[ process.env.SERVER_BASE_API ] >", process.env.SERVER_BASE_API);
	try {
		let { data } = await axios.post(`${process.env.SERVER_BASE_API}/api/v1/auth/update_place_websocket_address`, {
			address: `ws://${config.SERVER_IP}:${PORT}`,
			place_id: wrapConfig.PLACE_ID,
		});
		if (data.code == 200) {
			logger.info(`场地ID ${wrapConfig.PLACE_ID} 更新ws地址 http://${config.SERVER_IP}:${PORT}`);
		} else {
			logger.error(`场地ID ${wrapConfig.PLACE_ID} 更新ws地址失败http报错 ${data.message}`);
		}
	} catch (e) {
		logger.error(`场地ID ${wrapConfig.PLACE_ID} 更新ws地址失败 ${e}`);
	}
}

httpServer.listen(PORT, "0.0.0.0", () => {
	logger.info(`服务器运行在 http://${config.SERVER_IP}:${PORT}`);
	logger.info(`下载目录路径: http://${config.SERVER_IP}:${PORT}/downloads`);
	// 然后启动 UDP 服务器
	server.bind(() => {
		server.setBroadcast(true);
		logger.info("UDP广播服务器已启动");

		// 开始广播
		startBroadcast();
	});

	updatePlaceWebSocketAddress();
});

router.init(app);
